package com.orcwar.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import android.util.Log;

import com.orcwar.engine.OWGame;
import com.orcwar.engine.OWPlayer;
import com.orcwar.engine.OWTile;
import com.orcwar.engine.OWUnit;
import com.orcwar.engine.level.OWLevelBuilder.OWLevelParameters;
import com.orcwar.engine.tile.OWAttackTile;
import com.orcwar.gui.OWGUI;

public class OWController {

	/** The graphic user interface. */
	private OWGUI gui;
	
	/** The game manager (engine). */
	private OWGame game;
	
	/** The current player. */	
	private OWPlayer player;

	/** The currently selected unit. Null if no unit is selected. */
	private OWUnit selectedUnit;

	/**
	 * Constructor.
	 * @param game the game engine
	 * @param player the current player
	 */
	public OWController(OWGame game, OWPlayer player) {
		this.game = game;
		this.player = player;
	}
	
	/**
	 * When the user pushed the screen and hasn't released yet.
	 * @param x
	 * @param y
	 */
	public boolean onShowPressed(int x, int y) {
		// tile if the tile on which the user clicked
		OWTile tile = game.getMap().getTile(x, y);
		if (gui.isAttackModeEnabled()) {

			// Attack mode
			for(OWAttackTile attackTile : gui.getTilesToHighlighAttacks()) {
				if (attackTile.getId() == tile.getId()) {
					// Touched a tile where the unit can attack -> attack this
					// tile
					gui.getOnShowPressedAttackTileIds().add(tile.getId());
					if (attackTile.getLinkedTilesIds() != null) {
						gui.getOnShowPressedAttackTileIds().addAll(attackTile.getLinkedTilesIds());
					}
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * When the user remove it's finger from the screen.
	 * @param x the x location
	 * @param y the y location
	 */
	public void onUp(int x, int y) {
		if (gui.getOnShowPressedAttackTileIds() == null 
				|| gui.getOnShowPressedAttackTileIds().size() == 0
				|| !gui.isAttackModeEnabled()) return;
		
		OWTile tile = game.getMap().getTile(x, y);
		if (tile != null) {
			if (gui.getOnShowPressedAttackTileIds().get(0) == tile.getId()) {
				//Released the onShowPress on the tile highlighted : perform attack
				OWAttackTile attackTile = gui.getTileToHighlighAttack(tile);
				if(attackTile != null) {
					game.attack(selectedUnit, attackTile);
				}
				Log.i(this.getClass().getName(), "Released the screen INSIDE the onShowPress tile");
			} else {
				Log.i(this.getClass().getName(), "Released the screen outside the onShowPress tile");
			}
		}
		
		//Clear the onShowPress list
		this.gui.getOnShowPressedAttackTileIds().clear();
	}

	/**
	 * Handle a tap on the screen
	 * @param x
	 * @param y
	 */
	public void handleTap(int x, int y) {

		// Check if the UI isn't blocked
		if (gui.isActionsBlocked())
			return;
		
//		//Hide the onShowPress indicator
//		gui.getOnShowPressedAttackTileIds().clear();

		// tile is the tile on which the user clicked
		OWTile tile = game.getMap().getTile(x, y);
		if (tile == null) return;
		
		// Unit is the unit on which the user clicked (if any)
		OWUnit unit = tile.getCurrentUnit();
		
		//handleSpecialTileTap(tile);

		if (unit != null && (!gui.isAttackModeEnabled() || unit.equals(selectedUnit))) {
			// The tile contains a unit that we are not attacking
			// --> Select it
			handleUnitTap(unit);

		} else {
			// The tile is empty
			handleTileTap(tile, unit);

		}

	}

	/**
	 * Handle the tap on a unit.
	 * 
	 * @param unit
	 *            the unit on which the user tapped
	 */
	private void handleUnitTap(OWUnit unit) {
		if (selectedUnit != unit) {
			selectUnit(unit);
			Set<OWTile> possibleMoves = game.findPossibleTilesToMove(unit);
			Set<OWAttackTile> possibleAttacks = null;
			if (!player.containsUnit(unit)) {
				//show attacks from all positions the unit can go (since it's a unit
				//of the opposite team)
				possibleAttacks = game.findPossibleTilesToAttack(unit, possibleMoves);
			} else {
				//show attacks from current tile only
				possibleAttacks = game.findPossibleTilesToAttack(unit, null);
			}
			gui.highlightTiles(possibleMoves, possibleAttacks);
		} else {
			// Clear the selection if the user taps on the selected unit
			deselectUnit();
		}
	}

	/**
	 * Handle the tap on a tile.
	 * 
	 * @param tile
	 *            the tile on which the user tapped
	 * @param unit
	 * 			  the unit that was on this tile (is any)
	 */
	private void handleTileTap(OWTile tile, OWUnit unit) {
		boolean performedAction = false;
		if (selectedUnit != null && player.containsUnit(selectedUnit)) {
			if (gui.isAttackModeEnabled()) {

				// Attack mode
				OWAttackTile attackTile = gui.getTileToHighlighAttack(tile);
				if(attackTile != null) {
					// Touched a tile where the unit can attack -> attack this
					// tile
					game.attack(selectedUnit, attackTile);
					performedAction = true;
				} else {
					if (unit != null) {
						handleUnitTap(unit);
						performedAction = true;
					}
				}
				

			} else {

				// Tapping a tile has effects only when one of the user's units
				// is
				// selected since the user cannot make enemy units move nor
				// attack.
				if (tile.getId() == gui.getDestinationTileId()) {
					// The tile is the last tile with a red X (ie. the
					// destination),
					// which means that the user want the unit to move here
					List<OWTile> pathToFollow = new ArrayList<OWTile>(gui.getTilesToDisplayPath().keySet());
					game.move(selectedUnit, pathToFollow);
					gui.displayPath(null);
					performedAction = true;

				} else if (gui.getTilesToHighlighMove().contains(tile)) {
					// The tile is highlighted as a tile where the unit can go
					// --> pathfinding to place crosses into each tile from the
					// selected unit's one up to this tile.
					gui.displayPath(game.findPath(selectedUnit,
							selectedUnit.getTile(), tile));
					gui.setDestinationTileId(tile.getId());
					performedAction = true;

				}
				
			}
		}
		
		//If a unit was selected but the user clicks on an empty tile, deselect it
		if (!performedAction) {
			deselectUnit();
		}
	}
	
	public void pass() {
		game.pass(player);
		gui.clearHighlights();
	}
	
	public void onMoveOver(OWUnit unit) {
		if (unit.getAttackPoints() > 0 || unit.getMovePoints() > 0) {
			//If the unit still has attack or movement points, highlights the tiles
			//where it can interact.
			selectUnit(unit);
			gui.highlightTiles(game.findPossibleTilesToMove(unit),
					game.findPossibleTilesToAttack(unit, null));
		}
	}
	
	public void onAttackOver(OWUnit unit, List<OWUnit> attackedUnits, boolean success) {
		game.finishAttack(unit, success, attackedUnits);
	}
	
	public void selectUnit(OWUnit unit) {
		gui.clearHighlights();
		selectedUnit = unit;
	}
	
	public void deselectUnit() {
		gui.clearHighlights();
		selectedUnit = null;
	}
	
	//GETTERS / SETTERS
	
	public OWLevelParameters getCurrentGameInfo() {
		return game.getCurrentLevelInfo();
	}

	public OWGame getGame() {
		return game;
	}

	public void setGame(OWGame game) {
		this.game = game;
	}

	public OWPlayer getPlayer() {
		return player;
	}

	public OWGUI getGui() {
		return gui;
	}

	public void setGui(OWGUI gui) {
		this.gui = gui;
	}

	public OWUnit getSelectedUnit() {
		return this.selectedUnit;
	}
}
